package com.gitee.dupe.dict.service.impl;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.gitee.dolt.boot.service.SuperServiceImpl;
import com.gitee.dolt.cache.repository.CacheOps;
import com.gitee.dolt.core.cache.model.CacheKey;
import com.gitee.dolt.core.util.BizAssert;
import com.gitee.dolt.core.util.SpringUtils;
import com.gitee.dupe.common.cache.ParameterKeyCacheKeyBuilder;
import com.gitee.dupe.common.event.ParameterUpdateEvent;
import com.gitee.dupe.common.event.model.ParameterUpdate;
import com.gitee.dupe.dict.dao.ParameterMapper;
import com.gitee.dupe.dict.entity.Parameter;
import com.gitee.dupe.dict.service.IParameterService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * <p>
 * 业务实现类
 * 参数配置
 * </p>
 *
 * @author zuihou
 * @date 2020-02-05
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ParameterServiceImpl extends SuperServiceImpl<ParameterMapper, Parameter> implements IParameterService {

    private final ParameterKeyCacheKeyBuilder parameterKeyCacheKeyBuilder = new ParameterKeyCacheKeyBuilder();
    private final CacheOps cacheOps;

    @Override
    public boolean save(Parameter model) {
        BizAssert.isFalse(count(Wrappers.<Parameter>lambdaQuery().eq(Parameter::getKey, model.getKey())) > 0,
                StrUtil.format("参数key[{}]已经存在", model.getKey()));
        return SqlHelper.retBool(baseMapper.insert(model));
    }

    @Override
    public boolean updateById(Parameter model) {
        int count = count(Wrappers.<Parameter>lambdaQuery().eq(Parameter::getKey, model.getKey()).ne(Parameter::getId, model.getId()));
        BizAssert.isFalse(count > 0, StrUtil.format("参数key[{}]已经存在", model.getKey()));

        Parameter parameterDb = getById(model.getId());
        BizAssert.isFalse(BooleanUtil.isTrue(parameterDb.getReadonly()), "系统内置参数不允许修改");

        boolean bool = SqlHelper.retBool(getBaseMapper().updateById(model));
        if (bool) {

            cacheOps.del(parameterKeyCacheKeyBuilder.key(parameterDb.getKey()),
                    parameterKeyCacheKeyBuilder.key(model.getKey()));

            SpringUtils.publishEvent(new ParameterUpdateEvent(
                    new ParameterUpdate(model.getKey(), model.getValue(), parameterDb.getValue())
            ));
        }
        return bool;
    }

    @Override
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            return true;
        }
        List<Parameter> parameterList = super.listByIds(idList);
        if (parameterList.isEmpty()) {
            return true;
        }
        BizAssert.isTrue(parameterList.stream().allMatch(e -> !BooleanUtil.isTrue(e.getReadonly())),
                "系统内置参数不允许删除");
        boolean bool = SqlHelper.retBool(baseMapper.deleteBatchIds(idList));
        CacheKey[] keys = parameterList.stream()
                .map(item -> parameterKeyCacheKeyBuilder.key(item.getKey()))
                .toArray(CacheKey[]::new);
        cacheOps.del(keys);

        parameterList.forEach(model ->
                SpringUtils.publishEvent(new ParameterUpdateEvent(
                        new ParameterUpdate(model.getKey(), null, model.getValue())
                ))
        );
        return bool;
    }

    @Override
    public Parameter getByKey(String key) {
        Parameter parameter = getOne(Wrappers.<Parameter>lambdaQuery().eq(Parameter::getKey, key));
        return parameter;
    }

    @Override
    public String getValue(String key, String defVal) {
        String value = getValue(key);
        return StrUtil.nullToDefault(value, defVal);
    }

    @Override
    public String getValue(String key) {
        if (StrUtil.isEmpty(key)) {
            return null;
        }
        Function<CacheKey, String> loader = k -> {
            Parameter parameter = Optional.ofNullable(getByKey(key)).filter(Parameter::getEnabled).orElse(null);
            return parameter == null ? null : parameter.getValue();
        };
        CacheKey cacheKey = parameterKeyCacheKeyBuilder.key(key);
        return cacheOps.get(cacheKey, loader);
    }

    @Override
    public String getValueOrCreate(String key) {
        return getValueOrCreate(key, null);
    }

    @Override
    public String getValueOrCreate(String key, String initValue) {
        return getValueOrCreate(key, initValue, true);
    }

    @Override
    public String getValueOrCreate(String key, String initValue, boolean cache) {
        if (StrUtil.isEmpty(key)) {
            return null;
        }
        Supplier<String> supplier = () -> {
            Parameter pd = getByKey(key);
            if (pd == null) {
                pd = new Parameter().setEnabled(true).setKey(key).setName(key).setReadonly(true).setValue(initValue);
                save(pd);
            }
            Parameter parameter = Optional.ofNullable(pd).filter(Parameter::getEnabled).orElse(null);
            return parameter == null ? null : parameter.getValue();
        };
        if (cache) {
            Function<CacheKey, String> loader = k -> supplier.get();
            CacheKey cacheKey = parameterKeyCacheKeyBuilder.key(key);
            return cacheOps.get(cacheKey, loader);
        } else {
            return supplier.get();
        }
    }

    @Override
    public boolean setValue(String key, String value) {
        Parameter parameter = getByKey(key);
        parameter.setValue(value);
        super.updateById(parameter);
        CacheKey cacheKey = parameterKeyCacheKeyBuilder.key(key);
        try {
            cacheOps.del(cacheKey);
        } catch (Exception e) {
            return false;
        }
        return true;
    }
}
